Skip to content

fix(setup): replace dead executor PATH probe with importability check - #487

Open
ProtocolWarden wants to merge 2 commits into
mainfrom
claude/eloquent-herschel-074573
Open

fix(setup): replace dead executor PATH probe with importability check#487
ProtocolWarden wants to merge 2 commits into
mainfrom
claude/eloquent-herschel-074573

Conversation

@ProtocolWarden

Copy link
Copy Markdown
Owner

The bug

ensure_executor_installed("team-executor") + verify_executor() in src/operations_center/entrypoints/setup/main.py gated the interactive setup wizard on a step that could never pass:

  1. check_command_installed("team-executor")
  2. if absent → uv tool install git+https://github.com/ProtocolWarden/TeamExecutor.git@dev --force
  3. re-check PATH → raise typer.BadParameter("[executor] ERROR: installation failed")
  4. verify_executorteam-executor --help

TeamExecutor declares no [project.scripts], so no team-executor console script is ever produced. Verified against the live stack: shutil.which("team-executor") is None. Every setup run hard-failed at that gate — after burning a uv tool install network fetch first.

Why the probe was measuring the wrong thing

OC consumes all three execute backends as librariesbackends/{team_executor,dag_executor,critique_executor}/adapter.py each do a plain import <module>. So importability in OC's venv is the only readiness signal that means anything.

PATH is not: TeamExecutor and CritiqueExecutor ship no console script at all, and the one that does exist (DAGExecutor's dag-executor) is never invoked by OC.

The fix

missing_executor_backends() + ensure_executor_backends_installed(), mirroring the ensure_executor_backends() self-heal in scripts/operations-center.sh:

  • probe each backend with <venv-python> -c "import <module>"
  • install uv only if a backend is actually missing
  • install missing backends editable from their sibling checkouts (../TeamExecutor, ../DAGExecutor, ../CritiqueExecutor)
  • fail with the expected checkout path if a sibling isn't cloned
  • re-probe and fail if still not importable

The probe runs in a subprocess rather than via importlib in-process, so an install that lands partway through setup is visible to the re-check (the parent's import caches would still answer for the pre-install state).

Config-key decisions

Key Decision Why
team_executor.binary Removed No consumer in either direction — TeamExecutorSettings has no binary field, render_settings_yaml never wrote the key, and the only reader was setup's own prompt default.
OPERATIONS_CENTER_EXECUTOR_INSTALL_REF Kept, repurposed It does have a live consumer (maintenance/dependency_check.py), but its old meaning ("git ref to install from") died with ensure_executor_installed. Relabeled as a version pin for drift reporting — which is what dependency-check already did with it, and how the docs already grouped it alongside the Plane and provider CLI pins.

Second instance of the same bug

collect_dependency_statuses probed team-executor --version, so the TeamExecutor row reported healthy=False / "not installed or not on PATH" on every single run, forever. Replaced with executor_backend_status() (importability + best-effort distribution version via packages_distributions()); kind corrected "cli""library".

Known gap, deliberately not closed here

ensure_executor_backends() in scripts/operations-center.sh probes only import team_executor, dag_executor and reinstalls only two siblings. critique_executor is a third backend OC loads, so a uv sync/venv-recreate that drops it is not auto-repaired at fleet launch. Setup now covers all three; the launcher is the remaining gap.

Left alone deliberately — that's fleet-startup behavior, outside this change's blast radius. Tracked in .console/backlog.md under "Up Next".

Verification

Probed the live venv:

missing_executor_backends() -> []
team_executor      (True, '0.1.0')
dag_executor       (True, '0.1.0')
critique_executor  (True, '0.1.0')
shutil.which("team-executor") -> None      # the old gate could never pass
  • 10 new tests (7 in test_setup_cli.py, 3 in test_dependency_check.py); 26 pass across the two touched files
  • ruff check / ruff format --check clean
  • Full suite: 10354 passed, 6 failed — the same pre-existing sandbox/timing failures recorded in .console/backlog.md from prior stages, each reproduced on an unmodified checkout
  • custodian-multi against this worktree: 0 findings

Docs

  • docs/operator/setup.md — rewrote "Executor Install Behavior" (it described the broken flow as if it worked), fixed the "install/verify team-executor CLI" bullet and the Advanced Mode pin description
  • docs/demo.md — corrected the prerequisite telling operators to put team-executor on PATH

🤖 Generated with Claude Code

`ensure_executor_installed("team-executor")` + `verify_executor` gated
interactive setup on a console script that TeamExecutor never produces
(no `[project.scripts]`), so the wizard hard-failed at that step on every
run — after burning a `uv tool install` network fetch. Verified against
the live stack: `shutil.which("team-executor")` is None.

The probe measured the wrong thing. OC consumes all three execute
backends as LIBRARIES — backends/{team,dag,critique}_executor/adapter.py
each do a plain `import <module>` — so importability in OC's venv is the
only readiness signal that means anything. PATH is not: TeamExecutor and
CritiqueExecutor ship no console script at all, and the one that exists
(DAGExecutor's `dag-executor`) is never invoked by OC.

Replaced with `missing_executor_backends()` + `ensure_executor_backends_
installed()`, mirroring `ensure_executor_backends()` in
scripts/operations-center.sh: probe each backend with
`<venv-python> -c "import <module>"`, install missing ones editable from
their sibling checkouts, re-probe. Probing in a subprocess (not
importlib in-process) keeps a mid-run install visible to the re-check.

Config keys:

* `team_executor.binary` — removed. No writer (render_settings_yaml never
  emitted it), no settings field (TeamExecutorSettings has no `binary`),
  no reader outside setup's own prompt default.
* `OPERATIONS_CENTER_EXECUTOR_INSTALL_REF` — kept, repurposed. It has a
  live consumer in dependency_check.py, but its old meaning ("git ref to
  install from") died with ensure_executor_installed. Relabeled as a
  drift-reporting version pin, which is what that consumer already did
  with it.

Same stale-CLI bug had a second instance: collect_dependency_statuses
probed `team-executor --version`, so the TeamExecutor row reported
healthy=False / "not installed or not on PATH" on every run, forever.
Now uses `executor_backend_status()` (importability + best-effort
distribution version); `kind` corrected "cli" -> "library".

Setup covers all three backends; the shell self-heal still covers only
two — a dropped CritiqueExecutor is not yet auto-repaired at fleet
launch. Left alone deliberately (fleet-startup behavior, outside this
change's blast radius); tracked in .console/backlog.md under Up Next.

Verified against the live venv: missing_executor_backends() -> [], all
three backends report (True, '0.1.0'). 10 new tests; full suite 10354
passed with the same 6 pre-existing sandbox/timing failures, all
reproduced on an unmodified checkout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant